package com.guanyu.u2cache.redis;

import cn.hutool.core.util.ObjectUtil;
import com.guanyu.u2cache.cache.Level2Cache;
import com.guanyu.u2cache.manage.ListenerEventManag;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.LocalCachedMapOptions;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.concurrent.TimeUnit;

/**
 * @author zhouyunjian
 * @date 2023/11/27 11:15
 **/
@NoArgsConstructor
@Slf4j
public class Level2CacheImpl implements Level2Cache {

    @Value("#{'${spring.profiles.active:dev}'.split(',')}")
    public String env;
    @Autowired(required = false)
    private RedissonClient redissonClient;

    private String getCacheName(String name) {
        return name + "_" + this.env;
    }

    //    @Value("${level2cache.cache.valid.minutes:2}")
    private int cacheValidMinutes = 2;

    public Level2CacheImpl(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    @Override
    public Object getCache(String[] eventNames, String key, long expireTime, TimeUnit timeUnit) {
        for (String eventName : eventNames) {
            RMapCache rMapCache = redissonClient.getMapCache(getCacheName(eventName), getOption());
            log.debug("【缓存获取】二级缓存eventName[{}]下的key[{}]", eventName, key);
            Object o = rMapCache.get(key);
            if (ObjectUtil.isNotEmpty(o)) {
                return o;
            }
        }
        return null;
    }

    private LocalCachedMapOptions getOption() {
        LocalCachedMapOptions options = LocalCachedMapOptions.defaults()
                //弱引用清空数据，否则会有内存溢出的风险
                .evictionPolicy(LocalCachedMapOptions.EvictionPolicy.WEAK)
                //为0情况下不限制容量
                .cacheSize(0)
                //重连后清空信息
                .reconnectionStrategy(LocalCachedMapOptions.ReconnectionStrategy.CLEAR)
                //本地缓存元素变动，更新所有其他服务相同本地缓存
                .syncStrategy(LocalCachedMapOptions.SyncStrategy.UPDATE)
                //本地缓存保留时间
                .timeToLive(cacheValidMinutes, TimeUnit.MINUTES);
        return options;
    }

    @Override
    public void putCache(String[] eventNames, String key, Object result, Class returnType, long expireTime, TimeUnit timeUnit) {
        for (String eventName : eventNames) {
            // RLocalCachedMap localCachedMap = redissonClient.getLocalCachedMap(CacheType.LEVEL2CACHE.getName(), getOption());
            RMapCache rMapCache = redissonClient.getMapCache(getCacheName(eventName), getOption());
            log.debug("【缓存传入】eventName[{}]下的key[{}]放入二级缓存过期时间[{}]单位[{}]", eventName, key, expireTime, timeUnit);
            if (expireTime > 0) {
                rMapCache.put(key, result, expireTime, timeUnit);
            } else {
                rMapCache.put(key, result);
            }
        }
    }


    @Override
    public void clear(String[] eventNames, String key) {
        for (String eventName : eventNames) {
            //  RLocalCachedMap localCachedMap = redissonClient.getLocalCachedMap(CacheType.LEVEL2CACHE.getName(), getOption());
            RMapCache rMapCache = redissonClient.getMapCache(getCacheName(eventName), getOption());
            log.debug("【缓存清理】eventName[{}]下的key[{}]清理", eventName, key);
            rMapCache.remove(key);
        }
    }

    @Override
    public boolean isExistKey(String[] eventNames, String key) {
        for (String eventName : eventNames) {
            RMapCache rMapCache = redissonClient.getMapCache(getCacheName(eventName), getOption());
            log.debug("【缓存获取】二级缓存eventName[{}]下的key[{}]", eventName, key);
            Object o = rMapCache.get(key);
            return ObjectUtil.isNotEmpty(o);
        }
        return false;
    }

    @Override
    public void clear(String[] listenEventName) {
        for (String eventName : listenEventName) {
            String[] cacheNames = ListenerEventManag.getSingleton().getCacheNames(eventName);
            for (String cacheName : cacheNames) {
                RMapCache rMapCache = redissonClient.getMapCache(getCacheName(eventName), getOption());
                rMapCache.clear();
            }
        }
    }

}
